package com.qlogic.commons.utils.data;

import java.io.OutputStream;
import java.io.Serializable;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import com.qlogic.commons.utils.dates.DateUtils;
import com.qlogic.commons.utils.reflect.BeanUtils;
import com.qlogic.commons.utils.reflect.Property;
import com.qlogic.commons.utils.strings.StringUtils;

public class DataUtils implements Serializable {
	/**
	 * 
	 */
	private static final long serialVersionUID = -206048943888875358L;
	
	public static final String DEFAULT_DATE_FORMAT = "MM/dd/yyyy";

	
	public static String toJson (List list, Object [] props, Object idProperty) throws Exception {
		return toJson (list, props, idProperty, -1);
	}
	
	public static String toJson (List list, Object [] props, Object idProperty, int count) throws Exception {
		return toJson (list, props, idProperty, count, null);
	}
	
	public static String toJson (List list, Object [] props, Object idProperty, int count, String dateFormat) throws Exception {
		if (dateFormat == null) {
			dateFormat = DEFAULT_DATE_FORMAT;
		}
		StringBuffer buff = new StringBuffer (); 
		
		if (list == null || list.isEmpty ()) {
			buff.append ("{ 'rowsCount': 0, [] }\n");
		} 
		if (count <= 0) {
			count = list.size ();
		}
		buff.append ("{ 'rowsCount': ");
		buff.append (String.valueOf (count));
		buff.append (", 'rows': [\n");
		
		String jsonId = null;
		
		if (idProperty == null) {
			jsonId = "dataIndex";
		} else {
			if (idProperty instanceof String) {
				jsonId = (String)idProperty;
			} else if (idProperty instanceof Property) {
				jsonId = ((Property)idProperty).getName ();
			}
		}
		
		for (int i = 0; i < list.size (); i++) {
			Object object = list.get (i);
			if (object == null) {
				continue;
			}
			Object idValue = null;
			if (idProperty != null) {
				if (idProperty instanceof String) {
					idValue = BeanUtils.getPropertyValue (object, (String)idProperty);
				} else if (idProperty instanceof Property) {
					idValue = BeanUtils.executeProperty ((Property)idProperty, object, Property.GET, null);
				}
			} 
			if (idValue == null) {
				idValue = String.valueOf (i);
			}
			buff.append (("{ '" + getCorrectName(jsonId) + "': "));
			buff.append (idValue.toString ());
			buff.append (", ");
			for (int j = 0; j < props.length; j++) {
				Object value = null;
				if (props [j] instanceof String) {
					value = BeanUtils.getPropertyValue (object, (String)props [j]);
				} else if (props [j] instanceof Property) {
					value = BeanUtils.executeProperty ((Property)props [j], object, Property.GET, null);
				}
				if (value == null) {
					value = "";
				}
				if (Calendar.class.isAssignableFrom(value.getClass ())) {
					value = DateUtils.toString ((Calendar)value, dateFormat);
				} else if (Date.class.isAssignableFrom(value.getClass ())) {
					value = DateUtils.toString ((Date)value, dateFormat);
				}
				buff.append ("'");
				buff.append (getCorrectName(props [j]));
				buff.append ("': '");
				buff.append (value.toString ());
				buff.append ("'");
				if (j < (props.length - 1)) {
					buff.append (", ");
				}
			}
			buff.append ("}\n");
		}
		
		buff.append ("]\n}");
		return buff.toString();
	}
	
	public static String toXml (List list, Object [] props, Object idProperty, String encoding) throws Exception {
		return toXml (list, props, idProperty, encoding, -1);
	}
	
	public static String toXml (List list, Object [] props, Object idProperty, String encoding, int count) throws Exception {
		return toXml (list, props, idProperty, encoding, count, null);
	}
	
	public static String toXml (List list, Object [] props, Object idProperty, String encoding, int count, String dateFormat) throws Exception {
		
		if (dateFormat == null) {
			dateFormat = DEFAULT_DATE_FORMAT;
		}
		StringBuffer buff = new StringBuffer (); 
		
		buff.append ("<?xml version=\"1.0\" encoding=\"" + encoding + "\"?>");
		buff.append ("<dataset>");
		
		if (count <= 0) {
			count = (list == null) ? 0 : list.size ();
		}
		
		buff.append ("<rowsCount>");buff.append (count);buff.append ("</rowsCount>");
		
		if (list != null && !list.isEmpty ()) {
			
			String xmlId = null;
			
			if (idProperty == null) {
				xmlId = "dataIndex";
			} else {
				if (idProperty instanceof String) {
					xmlId = (String)idProperty;
				} else if (idProperty instanceof Property) {
					xmlId = ((Property)idProperty).getName ();
				}
			}
			
			for (int i = 0; i < list.size (); i++) {
				Object object = list.get (i);
				if (object == null) {
					continue;
				}
				Object idValue = null;
				if (idProperty != null) {
					if (idProperty instanceof String) {
						idValue = BeanUtils.getPropertyValue (object, (String)idProperty);
					} else if (idProperty instanceof Property) {
						idValue = BeanUtils.executeProperty ((Property)idProperty, object, Property.GET, null);
					}
				} 
				if (idValue == null) {
					idValue = String.valueOf (i);
				}
				buff.append ("<row>");
				buff.append ("<" + getCorrectName(xmlId) + ">");
				buff.append (idValue.toString ());
				buff.append ("</" + getCorrectName(xmlId) + ">");
				for (int j = 0; j < props.length; j++) {
					Object value = null;
					if (props [j] instanceof String) {
						value = BeanUtils.getPropertyValue (object, (String)props [j]);
					} else if (props [j] instanceof Property) {
						value = BeanUtils.executeProperty ((Property)props [j], object, Property.GET, null);
					}
					if (value == null) {
						value = "";
					}
					if (Calendar.class.isAssignableFrom(value.getClass ())) {
						value = DateUtils.toString ((Calendar)value, dateFormat);
					} else if (Date.class.isAssignableFrom(value.getClass ())) {
						value = DateUtils.toString ((Date)value, dateFormat);
					}
					buff.append ("<" + getCorrectName(props [j]) + ">");
					buff.append (value.toString ());
					buff.append ("</" + getCorrectName(props [j]) + ">");

				}
				buff.append ("</row>");
			}
			
		}
		buff.append ("</dataset>");
		return buff.toString();
	}
	
	public static String getCorrectName (Object prop) {
		if (prop instanceof String) {
			return StringUtils.replace ((String)prop, ".", "_");
		} else if (prop instanceof Property) {
			return StringUtils.replace (((Property)prop).getName (), ".", "_");
		}
		return "NONAME";
	}
	
	public static void toJson (List list, String [] props, String idProperty, OutputStream writer) throws Exception {
		writer.write (toJson (list, props, idProperty).getBytes ());
	}
}
